package com.zg.autoform.web;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zg.autoform.vo.DiyViewAllVo;
import com.zg.autoform.vo.SubDiyFormVo;
import com.zg.autoform.vo.WorkflowColumnVo;
import com.zg.autoform.vo.WorkflowStepDataViewVo;
import com.zg.autoform.web.req.AddViewReq;
import com.zg.autoform.web.req.FormIdReq;
import com.zg.autoform.web.req.ViewIdReq;
import com.zg.common.core.A;
import com.zg.common.core.R;
import com.zg.common.core.dao.BaseEntity;
import com.zg.common.core.dao.autoflow.dao.*;
import com.zg.common.core.dao.autoflow.entity.*;
import com.zg.common.core.dao.autoform.*;
import com.zg.common.core.util.CollectionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Zxb
 */
@RestController
@RequiredArgsConstructor
@Api(tags = {"视图管理"})
public class ViewController {
    private final DiyViewDao viewDao;
    private final DiyFormDao formDao;
    private final DiyColumnDao columnDao;
    private final DiyLayoutDao layoutDao;
    private final NamedParameterJdbcTemplate jdbcTemplate;
    private final SettleBizformDao settleBizformDao;
    private final SettleWorkflowStepInstanceDao settleWorkflowStepInstanceDao;
    private final AutoflowStepDao autoflowStepDao;
    private final AutoflowMainDao autoflowMainDao;
    private final AutoflowExtendsDao autoflowExtendsDao;
    private final SettleWorkflowInstanceLinkDao settleWorkflowInstanceLinkDao;

    @ApiOperation("视图列表")
    @PostMapping("/view/list")
    public R<List<DiyView>> list(@RequestBody @Validated FormIdReq formIdReq) {
        List<DiyView> list = viewDao.list(
                new LambdaQueryWrapper<DiyView>()
                        .eq(DiyView::getFormId, formIdReq.getFormId())
                .orderByDesc(BaseEntity::getCreateTime));
        return R.success(list);
    }

    @ApiOperation("新增视图")
    @PostMapping("/view/add")
    public R add(@RequestBody AddViewReq req) {
        DiyForm form = formDao.getById(req.getFormId());
        A.isInDatabase(form, "视图");
        if(viewDao.exists(new LambdaQueryWrapper<DiyView>()
                .eq(DiyView::getFormId, req.getFormId())
                .eq(DiyView::getName, req.getName()))){
            return R.error("该视图名称已存在");
        }
        DiyView view = new DiyView();
        view.setFormId(req.getFormId());
        view.setName(req.getName());
        view.setType(req.getType());
        viewDao.save(view);
        return R.success();
    }
    @ApiOperation("删除视图")
    @PostMapping("/view/del")
    public R del(@RequestBody List<Long> ids) {
        viewDao.removeBatchByIds(ids);
        return R.success();
    }
    @ApiOperation("获取视图基本信息")
    @PostMapping("/view/get")
    public R<DiyViewAllVo> get(@RequestBody @Validated ViewIdReq viewIdReq) {
        DiyViewAllVo diyViewAllVo = new DiyViewAllVo();
        DiyView diyView = viewDao.getOne(new LambdaQueryWrapper<DiyView>().eq(DiyView::getId, viewIdReq.getViewId()));
        diyViewAllVo.setDiyView(diyView);
        DiyForm form = formDao.getById(diyView.getFormId());
        diyViewAllVo.setDiyForm(form);
        //查询真实数据
        Map<String, Object> resultMap = new HashMap<>();
        Map<String, Object> extendMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(viewIdReq.getStepInstCode())){
            //继承处理
            SettleWorkflowStepInstance stepInstance = settleWorkflowStepInstanceDao.getOne(new LambdaQueryWrapper<SettleWorkflowStepInstance>().eq(SettleWorkflowStepInstance::getStepInstCode, viewIdReq.getStepInstCode()));
            AutoflowMain autoflowMain = autoflowMainDao.getOne(new LambdaQueryWrapper<AutoflowMain>().eq(AutoflowMain::getCode, stepInstance.getFlowCode()));
            AutoflowStep autoflowStep = autoflowStepDao.getOne(new LambdaQueryWrapper<AutoflowStep>().eq(AutoflowStep::getFlowId, autoflowMain.getId()).eq(AutoflowStep::getStepNo, stepInstance.getStepCode()));
            List<AutoflowExtends> extendsList = autoflowExtendsDao.list(new LambdaQueryWrapper<AutoflowExtends>().eq(AutoflowExtends::getTargetFlowId, autoflowMain.getId())
                    .eq(AutoflowExtends::getTargetStepId, autoflowStep.getId()).eq(AutoflowExtends::getTargetFormId, form.getId()));
            List<Long> stepIds = extendsList.stream().map(AutoflowExtends::getSourceStepId).distinct().collect(Collectors.toList());
            List<Long> flowIds = extendsList.stream().map(AutoflowExtends::getSourceFlowId).distinct().collect(Collectors.toList());
            Map<String,AutoflowStep>  stepMap=new HashMap<>();
            Map<String,AutoflowMain>  mainMap=new HashMap<>();
            if (CollectionUtil.isNotEmpty(stepIds)){
                List<AutoflowStep> autoflowSteps = autoflowStepDao.listByIds(stepIds);
                stepMap = autoflowSteps.stream().collect(Collectors.toMap(line -> line.getId()+"", line -> line));
            }
            if (CollectionUtil.isNotEmpty(flowIds)){
                List<AutoflowMain> sourceAutoflowMain = autoflowMainDao.list(new LambdaQueryWrapper<AutoflowMain>().in(AutoflowMain::getId, flowIds));
                mainMap = sourceAutoflowMain.stream().collect(Collectors.toMap(line -> line.getId()+"", line -> line));
            }
            List<SettleWorkflowInstanceLink> instanceLinks = settleWorkflowInstanceLinkDao.list(new LambdaQueryWrapper<SettleWorkflowInstanceLink>().eq(SettleWorkflowInstanceLink::getToInstCode, stepInstance.getInstCode()));
            List<String> instCodes = new ArrayList<>();
            instCodes.add(stepInstance.getInstCode());
            List<String> preInstCode = instanceLinks.stream().map(SettleWorkflowInstanceLink::getFromInstCode).distinct().collect(Collectors.toList());
            instCodes.addAll(preInstCode);
            Map<String, List<AutoflowExtends>> extendGroupMap = extendsList.stream().collect(Collectors.groupingBy(line -> {
                return line.getSourceStepId() + "," + line.getSourceFormId();
            }));
            Map<String, AutoflowStep> finalStepMap = stepMap;
            Map<String, AutoflowMain> finalMainMap = mainMap;
            extendGroupMap.forEach((k, v)->{
                String[] split = k.split(",");
                if (split.length==2){
                    String sourceStepId =split[0];
                    String sourceFormId =split[1];
                    AutoflowStep autoflowStep1 = finalStepMap.get(sourceStepId);
                    AutoflowMain autoflowMain1 = finalMainMap.get(autoflowStep1.getFlowId()+"");
                    SettleWorkflowStepInstance stepInstance1 = settleWorkflowStepInstanceDao.getOne(new LambdaQueryWrapper<SettleWorkflowStepInstance>()
                            .eq(SettleWorkflowStepInstance::getStepCode, autoflowStep1.getStepNo())
                            .eq(SettleWorkflowStepInstance::getFlowCode, autoflowMain1.getCode())
                            .in(SettleWorkflowStepInstance::getInstCode, instCodes).eq(SettleWorkflowStepInstance::getStepInstState,"2"));
                    if (ObjectUtil.isNotEmpty(stepInstance1)){
                        SettleBizform settleBizform = settleBizformDao.getOne(new LambdaQueryWrapper<SettleBizform>()
                                .eq(SettleBizform::getStepInstCode, stepInstance1.getStepInstCode()).eq(SettleBizform::getFormId, sourceFormId));
                        if (ObjectUtil.isNotEmpty(settleBizform)&&ObjectUtil.isNotEmpty(settleBizform.getBizFormId())){
                            Map<String, Object> realData = getRealData(settleBizform.getBizzTable(), settleBizform.getBizFormId());
                            v.forEach(extend->{
                                Object o = realData.get(extend.getSourceColumn());
                                if (ObjectUtil.isNotEmpty(o)){
                                    extendMap.put(extend.getTargetColumn(),String.valueOf(o));
                                }
                            });
                        }
                    }
                }
            });
            //查询真实数据
            SettleBizform settleBizform = settleBizformDao.getOne(new LambdaQueryWrapper<SettleBizform>().eq(SettleBizform::getFormId, form.getId())
                    .eq(SettleBizform::getStepInstCode, viewIdReq.getStepInstCode()));
            List<SubDiyFormVo> subDiyFormVos = new ArrayList<>();
            List<DiyForm> subForms = formDao.list(new LambdaQueryWrapper<DiyForm>().eq(DiyForm::getParId, form.getId()));
            subForms.forEach(subForm->{
                SubDiyFormVo subDiyFormVo = new SubDiyFormVo();
                subDiyFormVo.setName(subForm.getName());
                subDiyFormVo.setId(subForm.getId());
                subDiyFormVo.setCode(subForm.getCode());
                List<DiyColumn> subColumn = columnDao.list(new LambdaQueryWrapper<DiyColumn>().eq(DiyColumn::getFormId, subForm.getId()));
                subDiyFormVo.setColumns(subColumn);
                if (ObjectUtil.isNotEmpty(settleBizform.getBizFormId())){
                    List<Map<String, Object>> subResultMap=getRealPidData(subForm.getCode(),settleBizform.getBizFormId());
                    subDiyFormVo.setColumnData(subResultMap);
                }
                subDiyFormVos.add(subDiyFormVo);
            });
            diyViewAllVo.setSubDiyForm(subDiyFormVos);
            if (ObjectUtil.isNotEmpty(settleBizform.getBizFormId())){
                resultMap=getRealData(form.getCode(),settleBizform.getBizFormId());
            }
        }
        //获取所有布局
        List<DiyLayout> layoutList = layoutDao.list(new QueryWrapper<DiyLayout>().lambda().in(DiyLayout::getViewId, diyView.getId()));
        if (!CollectionUtils.isEmpty(layoutList)){
            //获取全部字段
            List<DiyColumn> columnList = columnDao.list(new QueryWrapper<DiyColumn>()
                    .lambda().eq(DiyColumn::getFormId, layoutList.get(0).getFormId()));
            List<WorkflowColumnVo> workflowColumnVos = new ArrayList<>();
            Map<String, Object> finalResultMap = resultMap;
            columnList.forEach(column->{
                WorkflowColumnVo workflowColumnVo = new WorkflowColumnVo();
                BeanUtil.copyProperties(column,workflowColumnVo);
                //填充继承数据
                if (CollectionUtil.isNotEmpty(extendMap)){
                    Object data= extendMap.get(column.getCode());
                    if (ObjectUtil.isNotEmpty(data)){
                        workflowColumnVo.setDefaultVal(String.valueOf(data));
                    }
                }
                //填充真实数据
                if (CollectionUtil.isNotEmpty(finalResultMap)){
                    Object data= finalResultMap.get(column.getCode());
                    if (ObjectUtil.isNotEmpty(data)){
                        workflowColumnVo.setDefaultVal(String.valueOf(data));
                    }
                }
                workflowColumnVos.add(workflowColumnVo);
            });
            List<WorkflowStepDataViewVo> viewVos = new ArrayList<>();
            layoutList.forEach(layout->{
                WorkflowStepDataViewVo workflowStepDataViewVo = new WorkflowStepDataViewVo();
                workflowStepDataViewVo.setId( layout.getColumnId());
                workflowStepDataViewVo.setSpan( layout.getSpan());
                workflowStepDataViewVo.setOffset( layout.getOffset());
                workflowStepDataViewVo.setSort( layout.getSort());
                workflowStepDataViewVo.setIsExist( false);
                DiyColumn column = columnList.stream()
                        .filter(c -> c.getId().equals(layout.getColumnId()))
                        .findFirst().orElse(null);
                if (columnList != null) {
                    workflowStepDataViewVo.setIsExist( true);
                    workflowStepDataViewVo.setName( column.getName());
                    workflowStepDataViewVo.setCode( column.getCode());
                    workflowStepDataViewVo.setCompType( column.getCompType());
                    workflowStepDataViewVo.setExtra( column.getExtra());
                    workflowStepDataViewVo.setDefaultVal( column.getDefaultVal());
                    workflowStepDataViewVo.setRegex(column.getRegex());
                    workflowStepDataViewVo.setErrorMsg(column.getErrorMsg());
                }
                viewVos.add(workflowStepDataViewVo);
            });
            diyViewAllVo.setViewInfoList(viewVos);
            diyViewAllVo.setAllColumns(workflowColumnVos);
        }
        return R.success(diyViewAllVo);
    }

    private List<Map<String, Object>> getRealPidData(String tableName, Long pId) {
        //过滤器
        StringBuffer conditionSb = new StringBuffer("par_id ="+pId);
        Map<String, Object> conditionMap = new LinkedHashMap<>();
        String sql = " SELECT * FROM " + tableName + " WHERE " + conditionSb;
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, conditionMap);;
        handleLongTypeProperty(list);
        return list;
    }

    private   Map<String, Object> getRealData(String tableName,Long id){
        Map<String, Object> resultMap = new HashMap<>();
        //过滤器
        StringBuffer conditionSb = new StringBuffer("id ="+id);
        Map<String, Object> conditionMap = new LinkedHashMap<>();
        String sql = " SELECT * FROM " + tableName + " WHERE " + conditionSb;
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, conditionMap);;
        handleLongTypeProperty(list);
        if (CollectionUtil.isNotEmpty(list)){
            resultMap=list.get(0);
        }
        return resultMap;
    }

    /**
     * 处理Long类型字段，转成字符串再传给前端，避免丢失精度
     */
    private void handleLongTypeProperty(List<Map<String, Object>> list) {
        String KEY = "ID";
        list.stream().forEach(m -> {
            m.put(KEY, String.valueOf(m.get(KEY)));
        });
    }

}
